home *** CD-ROM | disk | FTP | other *** search
/ SoundMaker 2003 (Professional Edition) / SoundMaker 2003 - Professional Edition.iso / midi tool / midioxse.exe / DATA.1 / fastarp.rex < prev    next >
OS/2 REXX Batch file  |  1999-03-27  |  5KB  |  178 lines

  1. /* REXX: Simple MIDI Arpeggiator */
  2. /* This Runs a fast single finger aprepggiator */
  3.  
  4. call RxFuncAdd 'SysLoadFuncs', 'RexxUtil', 'SysLoadFuncs'
  5. call SysLoadFuncs 
  6.  
  7. qName = MoxGetQueueName()
  8. oldq  = RxQueue( 'Set', qName )
  9. ret   = MOXSetQueueDataFormat( 'N' )
  10.  
  11. /* MIDI-OX creates a semaphore with same name as queue */
  12. sem = SysOpenEventSem( qName )
  13.  
  14. running = (sem <> 0)    
  15.  
  16. /* Use an Object REXX Queue to store note ons and offs */
  17. noteQ = .queue~new
  18. say "FastArp Initialized..."
  19.  
  20. do while running
  21.    someInput = (Queued() <> 0) 
  22.    someChord = (noteQ~Items() <> 0) 
  23.  
  24.    do while someInput | someChord 
  25.       now = MoxGetSystemTime()  
  26.       if someInput 
  27.       then do 
  28.          pull timestamp status data1 data2
  29.  
  30.          /* Sent by MIDI-OX to signify end of program */
  31.          if timestamp = 'END_DATA' 
  32.          then do
  33.             running = 0
  34.             leave
  35.          end
  36.  
  37.          if status = 144 
  38.          then do /* only notes */
  39.             later = now + 100
  40.             event = .NoteEvent~New( later, 11, status, data1, data2 )
  41.             noteQ~Queue( event )
  42.          end
  43.       end
  44.  
  45.       if someChord 
  46.       then do
  47.          /* see if the queue head has expired yet */
  48.          event = noteQ~Peek()
  49.          if event~HasExpired( now ) 
  50.          then do
  51.             /* actually remove from Queue */
  52.             event = noteQ~Pull()
  53.          
  54.             ret = MoxOutputMidi( event~status, event~note, event~velocity )
  55.             if ret <> 0 
  56.             then do
  57.                 msg = "Error code: " || ret
  58.                call RxMessageBox msg, '', 'OK', 'STOP'  
  59.             end
  60.  
  61.             if event~Cycle() then
  62.                noteQ~Queue( event )
  63.          end
  64.       end
  65.  
  66.       someInput = (Queued() <> 0) 
  67.       someChord  = (noteQ~Items() <> 0) 
  68.    end
  69.  
  70.    if running 
  71.    then do
  72.       /* queue is empty: you could do other processing here */       
  73.       ret = SysWaitEventSem( sem )
  74.       if ret <> 0 
  75.       then do
  76.          running = .false
  77.          call RxMessageBox "Sem Code:" || ret, "err", 'OK', 'STOP'          
  78.       end
  79.    end
  80. end
  81.  
  82. say "Exiting..."
  83. call SysDropFuncs 
  84. exit
  85.  
  86. /* ========================================================== */
  87.  
  88. ::class noteEvent subclass Object
  89. ::method Init
  90.   expose expire count status note velocity origNote
  91.   use arg expire, count, status, note, velocity 
  92.  
  93.   self~origNote = self~note
  94.   self~note = self~NextChordNote( self~note )
  95.   return
  96.  
  97. ::method expire   attribute
  98. ::method count    attribute 
  99. ::method status   attribute
  100. ::method note     attribute
  101. ::method velocity attribute
  102. ::method origNote attribute
  103.  
  104. ::method HasExpired
  105.   use arg now
  106.   
  107.   if now > self~expire then
  108.      return 1
  109.   return 0
  110.  
  111. ::method Cycle
  112.   self~count = self~count - 1 /* one less to go */
  113.  
  114.   select  
  115.      when self~count > 8 
  116.      then do
  117.         self~expire = self~expire + 100
  118.         self~note = self~NextChordNote( self~note )
  119.         return 1
  120.      end
  121.      when self~count > 5 
  122.      then do
  123.         self~expire = self~expire + 100
  124.         if self~count = 6 then
  125.            self~note = self~origNote 
  126.         else
  127.            self~note = self~PrevChordNote( self~note )
  128.         return 1
  129.      end
  130.      when self~count > 2 
  131.      then do
  132.         self~expire = self~expire + 100
  133.         self~note = self~NextChordNote( self~note )
  134.         return 1
  135.      end
  136.      when self~count > 0 
  137.      then do
  138.         self~expire = self~expire + 100
  139.         self~note = self~PrevChordNote( self~note )
  140.         return 1
  141.      end
  142.      otherwise return 0
  143.   end
  144.    
  145.   return 0
  146.  
  147. ::method NextChordNote
  148.   use arg lastNote
  149.   
  150.   /* use Key of C for simplicity */
  151.   remaind = (lastNote + 4) // 12
  152.   select  
  153.      when remaind = 1  then  nextnote = lastNote + 3
  154.      when remaind = 3  then  nextnote = lastNote + 3
  155.      when remaind = 6  then  nextnote = lastNote + 3
  156.      when remaind = 8  then  nextnote = lastNote + 3    
  157.      when remaind = 10 then  nextnote = lastNote + 3    
  158.      otherwise nextNote = lastNote + 4
  159.   end
  160.  
  161.   return nextNote
  162.  
  163. ::method PrevChordNote
  164.   use arg curNote
  165.   
  166.   /* use Key of C for simplicity */
  167.   remaind = curNote // 12
  168.   select  
  169.      when remaind = 1  then  prevnote = curNote - 4
  170.      when remaind = 4  then  prevnote = curNote - 4
  171.      when remaind = 6  then  prevnote = curNote - 4
  172.      when remaind = 9  then  prevnote = curNote - 4
  173.      when remaind = 11 then  prevnote = curNote - 4
  174.      otherwise prevNote = curNote - 3
  175.   end
  176.  
  177.   return prevNote
  178.